package com.bowlong.third.grizzly.filter;

import java.io.IOException;

import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.filterchain.BaseFilter;
import org.glassfish.grizzly.filterchain.FilterChainContext;
import org.glassfish.grizzly.filterchain.NextAction;
import org.glassfish.grizzly.memory.MemoryManager;

import com.bowlong.third.grizzly.codec.Message;

public final class Length2MessageFilter extends BaseFilter {

	@Override
	public NextAction handleRead(final FilterChainContext ctx)
			throws IOException {
		final Buffer sourceBuffer = ctx.getMessage();
		sourceBuffer.mark();

		final int sourceBufferLength = sourceBuffer.remaining();

		if (sourceBufferLength < 2) {
			sourceBuffer.reset();
			return ctx.getStopAction(sourceBuffer);
		}

		// Get the body length
		final int bodyLength = sourceBuffer.getShort();
		final int messageLength = bodyLength + 2;

		if (sourceBufferLength < bodyLength) {
			sourceBuffer.reset();
			return ctx.getStopAction(sourceBuffer);
		}

		final Buffer remainder = sourceBufferLength > messageLength ? sourceBuffer
				.split(messageLength) : null;

		final Message message = new Message(sourceBuffer, messageLength);
		ctx.setMessage(message);

		// We can try to dispose the buffer
		sourceBuffer.tryDispose();

		// Instruct FilterChain to store the remainder (if any) and continue
		// execution
		return ctx.getInvokeAction(remainder);
	}

	@SuppressWarnings("rawtypes")
	@Override
	public NextAction handleWrite(final FilterChainContext ctx)
			throws IOException {
		// Get the source GIOP message to be written
		final Message message = ctx.getMessage();

		byte[] body = message.body();
		short length = (short) body.length;
		final int size = 2 + length;

		// Retrieve the memory manager
		final MemoryManager memoryManager = ctx.getConnection().getTransport()
				.getMemoryManager();

		// allocate the buffer of required size
		final Buffer output = memoryManager.allocate(size);

		// Allow Grizzly core to dispose the buffer, once it's written
		output.allowBufferDispose(true);

		output.putShort(length);
		output.put(body, 0, length);

		// Set the Buffer as a context message
		ctx.setMessage(output.flip());

		// Instruct the FilterChain to call the next filter
		return ctx.getInvokeAction();
	}
}
